home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Technotools
/
Technotools (Chestnut CD-ROM)(1993).ISO
/
lang_asm
/
setpgms
/
env_set.asm
next >
Wrap
Assembly Source File
|
1987-01-14
|
27KB
|
702 lines
PAGE 60,132
;Usage is: call envsub ds:si -> length,string
; length is 1 byte long, <128
; if high bit on, primary environment is set.
; string is of form: name=value
; Copyright 1987, A. B. Krueger GPW MI 48236
; All rights reserved. Contact "ARNY KRUEGER"
; at the EXEC-PC BBS (414-964-5160) for permission
; to use commercially.
;
;Clone of SET command that demonstrates updating
; the environment string.
;If there is no secondary command processor, the
; global environment is updated
;If there is a secondary command processor, then
; its enviroment is updated
sb segment at 0 ;equates storage blocks and psp's
sb_kind db ' ' ;type of storage block: 'M' or 'Z'
sb_psp dw ? ;psp segment address
sb_length dw ? ;sb length in paragraphs
sb_head_length equ 10h ;length of sb header
org 0h ;program segement prefix equates
psp_ret_int dw ? ;int 20h
org 2Ch
psp_env dw ? ;segment address of environment
org 50h
psp_dos_function dw ? ;address of function dispatcher
org 80h
psp_parm_string db ? ;1 byte length plus parm string
psp_length equ 100h
sb ends
code_seg segment para public
assume cs:code_seg,ds:code_seg,es:sb
public env_set
;local data
cr equ 13
lf equ 10
sb_count dw 0 ;count of sb's encountered
sb_shell dw 0 ;segment address of shell sb
sb_shell_env dw 0 ;segment address of global env sb
sb_secondary dw 0 ;segment address of secondary command.com
sb_secondary_env dw 0 ;segment address of secondary command env
fatal_msg equ 80h
error_msg equ 40h
info_msg equ 20h
msg_flag db fatal_msg+error_msg
db 'Copyright 1987, A. B. Krueger GPW MI 48236'
secondary_msg db info_msg,'Secondary '
command_found db info_msg,'COMMAND.COM found',cr,lf,'$'
bad_dos_msg db fatal_msg,'Must be running under DOS 2.0 or above',cr,lf,'$'
bad_sb_msg db fatal_msg,'Bad storage block',cr,lf,'$'
bad_env_msg db error_msg,'Bad environment block',cr,lf,'$'
command_lost db error_msg,'Shell never found',cr,lf,'$'
addbadmsg db error_msg,'Environment corrupt',cr,lf,'$'
addmsg db info_msg,'Addition requested',cr,lf,'$'
removemsg db info_msg,'Removal requested',cr,lf,'$'
env_set_nospace db error_msg,'No space in environment string',cr,lf,'$'
env_set_syntax db error_msg,'Set string syntax error',cr,lf,'$'
type_string proc near ;type message at offset in dx
push ax ;save registers
push cx
push dx
push si
mov si,dx ;get message level
lodsb
and al,msg_flag ;compare to what sells
jz type_ret ;if not on list, send to bit bucket
mov dx,si
mov ax,0900h
int 21h
type_ret:
pop si
pop dx
pop cx
pop ax
ret
type_string endp
get_first_sb proc near ;get first storage block, point es at it
push ax
push bx
mov ax,5200h
int 21h ;es:bx points to memory block anchor+2
dec bx
dec bx
mov es,es:[bx] ;get first memory block address into es
pop bx
pop ax
ret
get_first_sb endp
get_next_sb proc near
push ax
mov ax,es ;get current paragraph
add ax,sb_length ;add in number of paragraphs
inc ax ;add 1 for header
mov es,ax ;set new extra segment address
pop ax
ret
get_next_sb endp
find_secondary_env proc near ;find env sb's for current program sb
push ax ;pointed to by es
push es
mov ax,es ;get address of secondary cp's sb
inc ax ;get its psp address
find_secondary_env_loop:
call get_next_sb ;get next sb
cmp ax,sb_psp ;match secondary's psp?
jne find_secondary_env_next ;if not, skip
mov sb_secondary_env,es ;otherwise, save
jmp find_secondary_env_exit ;and check no further
;lest we trash a .BAT block
find_secondary_env_next:
cmp sb_kind,'Z' ;last block?
jne find_secondary_env_loop
find_secondary_env_exit:
pop es
pop ax
ret
find_secondary_env endp
command_test proc near ;test program storage block at es:0
push ax
push bx
push cx
push dx
push ds
push es
push si
cmp sb_count,2
ja command_second
mov dx,offset command_found
call type_string
mov sb_shell,es
jmp command_test_good
command_second:
cmp sb_shell,0 ;did we find shell?
je command_first_bad ;if not, error
cmp word ptr es:psp_env+sb_head_length,0 ;check environment of program
je command_test_good ;if no environment, quit
push sb_shell
pop ds ;ds points to shell
mov al,byte ptr es:sb_head_length+psp_length
cmp al,0E9h ;a JMP?
jne command_test_good ;if not, no harm done
cmp al,byte ptr ds:sb_head_length+psp_length ;check 1st instruction
jne command_first_bad
mov si,sb_head_length+psp_length
mov di,sb_head_length+psp_length
mov cx,10 ;look at 10 words of code
repz cmpsw
clc
jcxz command_test_found ;if they all match, fine
jmp command_test_good ;if not, no harm done
command_test_found:
push cs
pop ds
mov sb_secondary,es
mov ax,es:psp_env+sb_head_length ;get env address
dec ax ;back up over sb header
mov sb_secondary_env,ax ;and save it
call find_secondary_env ;look for other env's
mov dx,offset secondary_msg
call type_string
jmp command_test_good
command_first_bad:
mov dx,offset command_lost
call type_string
stc
jmp command_test_end
command_test_good:
clc
command_test_end:
pop si
pop es
pop ds
pop dx
pop cx
pop bx
pop ax
ret
command_test endp
prog_test proc near ;test block for program
push ax ;save registers
push cx
push dx
push es
mov ax,sb_psp ;get PSP of owner
cmp ax,0 ;if zero, it is free
je prog_exit
cmp ax,8 ;if PSP of owner is at 8
je prog_exit ;block owned by config.sys
sub ax,sb_head_length ;get address of sb containg program
cmp ax,sb_shell ;is owner the primary shell?
je prog_exit
push es
pop ax
cmp ax,sb_psp ;compare to address of owner
ja prog_exit ;if owner below SB, system-owned
add ax,sb_length ;add in length
cmp ax,sb_psp ;compare to owner's PSP
JB prog_exit ;if end below owner PSP, no program
cmp sb_length,10 ;is block long enough to have a psp?
jbe prog_exit ;if not, no program
mov ax,word ptr es:psp_dos_function+sb_head_length
cmp ax,word ptr cs:psp_dos_function ;check PSP validity
jne prog_exit
mov ax,word ptr es:psp_ret_int+sb_head_length
cmp ax,word ptr cs:psp_ret_int ;check PSP validity
jne prog_exit ;if invalid, skip looking for env
call command_test
clc
prog_exit:
pop es ;restore registers
pop dx
pop cx
pop ax
ret
prog_test endp
sb_scan proc near ;loop cx storage blocks
mov al,sb_kind ;get storage block type byte
cmp al,04dh ;ordinary storage block
je sb_scan_got
cmp al,05ah
jne sb_scan_bad
mov cx,1 ;last block
sb_scan_got:
inc sb_count ;count storage blocks
cmp sb_count,3
jne sb_scan_not_global
mov sb_shell_env,es
jmp sb_scan_get
sb_scan_not_global:
call prog_test ;look for program
loop sb_scan_get
jmp sb_scan_end
sb_scan_get:
call get_next_sb
jmp sb_scan
sb_scan_end:
clc
jmp sb_scan_exit
sb_scan_bad:
mov al,2
mov dx,offset bad_sb_msg
stc
sb_scan_exit:
ret
sb_scan endp
sb_anal proc near ;proc to analyze storage blocks
; to find environment(s)
push ax
push cx
push dx ;carry flag = error
push es ;error level in al
mov ah,30h ;get release number
int 21h
cmp al,01h ;above dos 1.x?
jna sb_bad_dos
cld ;clear direction flag
call get_first_sb
mov cx,9999 ;scan all blocks
call sb_scan
jc sb_send_msg ;if any errors, exit
jmp sb_exit
sb_bad_dos:
mov al,1
mov dx,offset bad_dos_msg
stc
jmp sb_send_msg
sb_bad_env:
mov al,3
mov dx,offset bad_env_msg
stc
sb_send_msg:
pushf
call type_string
popf
sb_exit:
pop es
pop dx
pop cx
pop ax
ret
sb_anal endp
make_upper proc near ;make cx bytes at es:di upper case
push ax ;save registers modified
push cx
push di
push ds
push si
push es
pop ds
mov si,di
make_upper_loop:
lodsb ;get a byte
cmp al,'a' ;if lower case:
jb make_upper_next
cmp al,'z'
ja make_upper_next
and al,255-'a'+'A' ;make upper case
make_upper_next:
stosb ;store out results
loop make_upper_loop
pop si ;restore registers
pop ds
pop di
pop cx
pop ax
ret
make_upper endp
env_var_name proc near ;find environment variable name at
push ax ; ds:si, length in cx
push bx ;at exit, ds:di points to name
push di ; name length in cx
push es ;variable contents length to dx
push cx ;save length and pointer
push si ;for error exits
jcxz env_var_name_bad ;if length is 0, exit
push cs ;scan works at es:di
pop es
mov di,si
mov al,' ' ;scan for non-blank
env_var_strip:
repz scasb ;look for non-blank
jcxz env_var_name_bad ;if all blank, error!
inc cx ;back up over non-blank character
dec di
mov si,di ;save start of non-blank string
mov bx,cx ;save length
repnz scasb ;look for a blank
mov dx,di ;save location of ' ' or end
mov cx,bx ;reset search length
mov di,si ;reset search pointer
mov al,'=' ;search for equals sign
repnz scasb
jne env_var_name_bad ;if not found, error
cmp di,dx ;compare location of '=' and ' '
ja env_var_name_bad ;found ' ' first? then exit
mov dx,bx ;restore search length
add dx,si ;add start
sub dx,di ;subtract where '=' was
pop ax ;pop old si from stack
pop ax ;pop old cx from stack
mov cx,di ;where we found '='
sub cx,si ;subtract string start
dec cx ;minus 1 for '='
clc ;all is well
jmp env_var_name_exit
env_var_name_bad:
pop si ;restore pointer and length
pop cx
xor dx,dx ;contents length assumed zero
stc ;problems - set carry
env_var_name_exit:
pop es
pop di
pop bx ;restore registers
pop ax
ret
env_var_name endp
get_sb_size proc near ;get byte size of sb at es:0 in cx
push ax
mov ax,sb_length ;get length of env in paragraphs
mov cl,4 ;times 16
shl ax,cl
mov cx,ax
pop ax
ret
get_sb_size endp
env_var_find proc near ;find environment variable
;named in ds:si,name length in cx
;return string start in es:di
;length of entire string in cx
push ax ;save registers
push bx
push dx
mov bx,cx ;save length of name
push es ;save env block address
push ds ;set es:di to source string
pop es ; "
mov di,si ;make name upper case
call make_upper ;altering input string
pop es ;restore es to environment block
call get_sb_size ;get size of sb in bytes
mov di,sb_head_length ;start at data portion of block
mov dx,cx ;save block length
env_var_find_loop:
push si ;save string pointers
push di
mov cx,bx ;compare for length of name
mov ah,1 ;say not compare
repz cmpsb ;compare item to name for name length
jne env_var_find_next ;if not found, scan on
cmp byte ptr es:[di],'=' ;check next byte for '='
jne env_var_find_next ;if found, go calc length
mov ah,0 ;say compare ok
env_var_find_next:
pop di ;restore string pointers
pop si
xor al,al ;look for end of current substring
mov cx,dx ;search remainder of string
mov dx,di ;save search start
repnz scasb ;search for a zero
jne env_var_find_end ;none found, error
cmp ah,0 ;did original compare fly?
je env_var_find_found;if so, then pass length, etc
cmp byte ptr es:[di],0 ;check next byte for zero
je env_var_find_end ;if found, name not found
mov dx,cx ;save length of string remaining
jmp env_var_find_loop ;and loop on
env_var_find_end:
xor cx,cx ;length = 0, none found
stc ;set error flag
jmp env_var_find_exit
env_var_find_found:
mov cx,di ;save count of end of string
mov di,dx ;restore search start
sub cx,di ;calc length of search
dec cx ;less length of zero
clc ;no errors
env_var_find_exit:
pop dx
pop bx ;restore registers
pop ax
ret
env_var_find endp
null_var dw -1
env_var_add proc near ;add environment variable
;expression ->ds:si, length in cx
push ax ;save registers
push bx
push dx
mov dx,offset addmsg
call type_string
mov bx,cx
push si
mov si,offset null_var ;send on wild goose chase
mov cx,2 ;looking for x'ffff'
call env_var_find ;es:di points to end of env
pop si
jnc env_var_add_env_bad
;es:di now points to end of env
call get_sb_size ;get length of env area in cx
add cx,sb_head_length ;add head length for offsets
sub cx,bx ;deduct length of string
sub cx,2 ;deduct length of flag
cmp di,cx ;compare to where we add
ja env_var_add_bad ;if no space, too bad
mov cx,bx ;length of string to add
rep movsb ;do the deed
xor ax,ax ;make flag of two zeros
stosw ;add is on
jmp env_var_add_good
env_var_add_env_bad:
mov dx,offset addbadmsg
call type_string
env_var_add_bad:
stc
jmp env_var_add_exit
env_var_add_good:
clc
env_var_add_exit:
pop dx ;restore registers
pop bx
pop ax
ret
env_var_add endp
env_var_remove proc near ;remove environment variable
;at es:di, length in cx
push cx
push dx
push ds
push di
push si
cld ;move left to right
mov dx,offset removemsg
call type_string
inc cx ;add 1 for zero byte
mov dx,cx ;save length of var
call get_sb_size ;cx gets length of env area
add cx,sb_head_length ;add header length for offsets
sub cx,di ;deduct where we start
sub cx,dx ;deduct length of removed variable
mov si,di ;move from next variable
add si,dx ;add my length
push es ;do all the work in es:
pop ds
rep movsb ;do the move
pop si
pop di
pop ds
pop dx
pop cx
ret
env_var_remove endp
env_set proc near ;change environment per ds:si
push ax
push bx ;ds:si points to:
push cx ; length db ?
push di
push ds ; data db 'name=value'
push es
push si
xor ax,ax ;set length of local set string
lodsb ;get length, push di forward
mov cx,ax ;length of set string in cx
and cl,0ffh-80h ;length < 128
call sb_anal ;analyze the storage block chain
;to find command processor(s)
and al,80h ;was use primary switch on?
jnz env_set_shell ;if so, skip secondaries
cmp sb_secondary_env,0 ;is there a secondary command proc?
je env_set_shell ;if not, use primary
mov es,sb_secondary_env ;command processor is secondary
jmp env_set_command
env_set_shell: ;command processor is shell
mov es,sb_shell_env
env_set_command:
call env_var_name ;find what we want set at call
;ds:si -> expression, cx has length
;at return ds:si -> name
;cx is length of name
jc env_set_syntax_err ;if not found, error
mov bx,cx ;calculate new length of set string
inc bx ;add 1 for '='
add bx,dx ;add length of set string
call env_var_find ;find variable in environment block
;at return, es:di -> start of env str
;cx is length of env str
jc env_set_add ;if not found, just add
call env_var_remove ;remove variable at es:di from env
cmp dx,0 ;check out length of data to add
je env_set_exit ;if zero, just exit
env_set_add:
mov cx,bx ;restore length of variable
call env_var_add ;add new variable to set string
jc env_set_no_space
jmp env_set_exit
env_set_no_space:
mov dx,offset env_set_nospace
jmp env_set_type
env_set_syntax_err:
mov dx,offset env_set_syntax
env_set_type:
push cs
pop ds
call type_string
env_set_error:
stc
env_set_exit:
pop si
pop es
pop ds
pop di
pop cx
pop bx
pop ax
ret
env_set endp
code_seg ends
end